package com.nulldev.util.concurrency.threadIt.v4.emapi.compat;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.nulldev.util.concurrency.threadIt.v3.extensions.TaskStatus;
import com.nulldev.util.concurrency.threadIt.v4.emapi.ft.FutureTask;
import com.nulldev.util.data.Variables;

public class ExecutableRunnableFuture<V> extends FutureTask<V> implements Future<V>, RunnableFuture<V> {

	private final Runnable callable;
	private final V result;

	public ExecutableRunnableFuture(final Runnable callable, final V result) {
		super();
		Variables.requireNonNull(callable, "callable");
		this.callable = callable;
		this.result = result;
	}

	@Override
	public boolean cancel(final boolean mayInterruptIfRunning) {
		return super.requestCancel();
	}

	@Override
	public boolean isCancelled() {
		return super.status() == TaskStatus.CANCELLED || super.status() == TaskStatus.KILLED;
	}

	@Override
	public boolean isDone() {
		return this.completed();
	}

	@Override
	public V get() throws InterruptedException, ExecutionException {
		try {
			return super.waitTillCompletion();
		} catch (Throwable ex) {
			if (ex instanceof InterruptedException)
				throw ((InterruptedException) ex);
			throw new ExecutionException(ex);
		}
	}

	@Override
	public V get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
		try {
			return super.waitFor(timeout, unit);
		} catch (Throwable ex) {
			if (ex instanceof TimeoutException)
				throw ((TimeoutException) ex);
			if (ex instanceof InterruptedException)
				throw ((InterruptedException) ex);
			throw new ExecutionException(ex);
		}
	}

	@Override
	public V execute() {
		try {
			this.callable.run();
			return this.result;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
